﻿using Microsoft.Extensions.Caching.Distributed;

namespace Sunxsh.Es.Common.Redis;

/// <summary>
/// 基于Redis的封装，加入了前缀以分组，以及常用的api
/// </summary>
public class CacheRepo<T>(string groupName)
{
	string _groupName = groupName;
    RedisCacheHelper<T> _helper = new();

    public T GetOrDefault(string key, T defaultValue = default)
	{
		return _helper.TryGetValue(getFullKey(key), out var value)
			       ? value
			       : defaultValue;
	}

	/// <summary>
	/// 查询或创建
	/// </summary>
	public T GetOrCreate(string key, Func<T> factory, TimeSpan? expire, CacheExipreType expireType = CacheExipreType.Sliding)
	{
		var fullKey = getFullKey(key);
		if (_helper.TryGetValue(fullKey, out var value))
		{
			return value;
		}

		var opt    = toCacheOption(expire, expireType);
		var nValue = factory();
		_helper.SetValue(fullKey, nValue, opt);

		return nValue;
	}

	/// <summary>
	/// 设置缓存
	/// 默认滑动窗口超时 (读取时会重置超时时间)
	/// </summary>
	public void Set(string key, T value, TimeSpan expire, CacheExipreType expireType = CacheExipreType.Sliding)
	{
		var option = toCacheOption(expire, expireType);
		_helper.SetValue(getFullKey(key), value, option);
	}

	public void Remove(string key)
	{
		_helper.Remove(getFullKey(key));
	}


	/// <summary>
	/// 遍历所有对象，性能较低，生产环境尽量不要使用
	/// </summary>
	public IEnumerable<T> AllItems()
	{
		var keyPrefix = getFullKey("*");
		foreach (var redisKey in  RedisClient.Server.Keys(-1, keyPrefix))
		{
			if (_helper.TryGetValue(redisKey, out var data))
				yield return data;
		}
	}
	
	DistributedCacheEntryOptions toCacheOption(TimeSpan? expire, CacheExipreType expireType)
	{
		return new DistributedCacheEntryOptions()
		{
			SlidingExpiration               = expireType == CacheExipreType.Sliding ? expire : null,
			AbsoluteExpirationRelativeToNow = expireType == CacheExipreType.Absolute ? expire : null,
		};
	}
	
	string getFullKey(string key) => RedisConfig.GetFullKey(_groupName, key);
}

public enum CacheExipreType
{
	/// <summary>
	/// 弹性模式超时 （读取时重置超时时间） 
	/// </summary>
	Sliding,

	/// <summary>
	/// 绝对时间超时 （读取时不重置超时时间）
	/// </summary>
	Absolute,
}